//
//  UpdateFirmwaveViewController.m
//  CoolMove
//
//  Created by CA on 15/4/27.
//  Copyright (c) 2015年 CA. All rights reserved.
//

#import "UpdateFirmwaveViewController.h"
#import "PNChart.h"
#import "ColorEnum.h"
#import "CommunicationManager.h"
#import <MBProgressHUD/MBProgressHUD.h>
#import "FlatUIKit.h"

#import "FUIAlertView+customizeAppearance.h"

#import <CoreBluetooth/CoreBluetooth.h>
#import "DFUOperations.h"
#import "Constants.h"
#import "SSZipArchive.h"
#import "UnzipFirmware.h"
#import "Utility.h"
#import "DFUHelper.h"

static NSString * const kNotifyDelloc = @"UpdateFinish";

@interface UpdateFirmwaveViewController () <DFUOperationsDelegate, UIGestureRecognizerDelegate>
@property (weak, nonatomic) IBOutlet UIView *processBackgroundView;
@property (nonatomic, strong) PNCircleChart *processCircleChart;
@property (weak, nonatomic) IBOutlet UIView *popView;
@property (weak, nonatomic) IBOutlet UILabel *tipsLabel;

@property (strong, nonatomic) CBPeripheral *selectedPeripheral;
@property (strong, nonatomic) DFUOperations *dfuOperations;
@property (strong, nonatomic) DFUHelper *dfuHelper;

@property BOOL isTransferring;
@property BOOL isTransfered;
@property BOOL isTransferCancelled;
@property BOOL isConnected;
@property BOOL isErrorKnown;

@property (nonatomic, assign) BOOL isFinishingBootLoader;   // 是否已经完成协议栈升级
@property (nonatomic, assign) BOOL isFinishingApplication;  // 是否已经完成固件程序升级

@property (strong, nonatomic)NSString *selectedFileType;

@property (weak, nonatomic) IBOutlet UILabel *topTitleLabel;
@property (weak, nonatomic) IBOutlet UILabel *waitingDescriptionLabel;
@property (weak, nonatomic) IBOutlet UILabel *tipsContentLabel;
@end

@implementation UpdateFirmwaveViewController
{
    __block NSUInteger _retryCount;
}

@synthesize selectedPeripheral;
@synthesize dfuOperations;
@synthesize selectedFileType;

#pragma mark - View LifeCycle

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        PACKETS_NOTIFICATION_INTERVAL = 10;
        NSLog(@"PACKETS_NOTIFICATION_INTERVAL %d",PACKETS_NOTIFICATION_INTERVAL);
        dfuOperations = [[DFUOperations alloc] initWithDelegate:self];
        self.dfuHelper = [[DFUHelper alloc] initWithData:dfuOperations];
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self configureLocalization];
    [self addProcessCircle];
    [self updateThemeUI];
    [self configureDFUSetting];
    [self updateFirmwave];
    [self configureNotification];
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    
    [[NSNotificationCenter defaultCenter] postNotificationName:kNotifyDelloc object:nil];
}

- (void)dealloc
{
    NSLog(@"dealloc: %@", self);
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - Notification

- (void)configureNotification
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTurnOffBluetoothByHand:) name:kBLEOperationsBluetoothDidPowerOffNotification object:nil];
}

- (void)handleTurnOffBluetoothByHand:(NSNotification *)notification
{
    if (_isTransferring) {
        self.isErrorKnown = YES;
        [self showFailAlertView];
        [self close];
        [[LGCentralManager sharedInstance] configureSetting];
    }
}

#pragma mark - Localization

- (void)configureLocalization
{
    self.topTitleLabel.text = NSLocalizedString(@"Firmware upgrading", nil);
    self.waitingDescriptionLabel.text = NSLocalizedString(@"Wait a moment", nil);
    self.tipsLabel.text = NSLocalizedString(@"Tennis's firmware is being upgraded, do not let hardware away from the phone range, and maintain the hardware is opening", nil);
}

#pragma mark - Private Method

- (void)configureDFUSetting
{
    PACKETS_NOTIFICATION_INTERVAL = 10;
    NSLog(@"PACKETS_NOTIFICATION_INTERVAL %d",PACKETS_NOTIFICATION_INTERVAL);
    dfuOperations = [[DFUOperations alloc] initWithDelegate:self];
    self.dfuHelper = [[DFUHelper alloc] initWithData:dfuOperations];
    
    if (self.shouldUpdateBootLoader) {
        [self configureSelectedFileType:FIRMWARE_TYPE_BOTH_SOFTDEVICE_BOOTLOADER];
    } else {
        self.isFinishingBootLoader = YES;
        [self configureSelectedFileType:FIRMWARE_TYPE_APPLICATION];
    }
    
    [self onFileSelected:self.filePathUrl];
}

- (void)updateThemeUI
{
    self.popView.backgroundColor = kSearchViewBackgroundColor;
}

- (void)addProcessCircle
{
    self.processCircleChart = [self addCircleChartInView:self.processBackgroundView circleStrokeColor:kSelectedColor total:@100 current:@0];
    [self.processCircleChart strokeChart];
}

- (PNCircleChart *)addCircleChartInView:(UIView *)backgroundView
                      circleStrokeColor:(UIColor *)strokeColor
                                  total:(NSNumber *)total
                                current:(NSNumber *)current
{
    PNCircleChart *circleChart = [[PNCircleChart alloc] initWithFrame:backgroundView.bounds total:total current:current clockwise:NO shadow:YES shadowColor:kBackgroundColorLight displayCountingLabel:YES];
    circleChart.strokeColor = strokeColor;
    circleChart.chartType = PNChartFormatTypePercent;
    circleChart.countingLabel.font = [UIFont fontWithName:@"HelveticaNeue-thin" size:35];
    circleChart.countingLabel.textColor = [UIColor colorWithHex:0x7C7B80];
    [backgroundView addSubview:circleChart];

    return circleChart;
}

- (void)close
{
    [self dismissFromParentViewControllerWithAnimationType:DetailViewControllerAnimationTypeFade];
    if (self.dismissBlock) {
        self.dismissBlock();
        self.dismissBlock = nil;
    }
}

- (void)addGestureRecognizer
{
    UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(close)];
    gestureRecognizer.cancelsTouchesInView = NO;
    gestureRecognizer.delegate = self;
    [self.view addGestureRecognizer:gestureRecognizer];
}

#pragma mark - UIGestureRecognizer Delegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return (touch.view == self.view);
}

- (void)updateFirmwave
{
    
    if ([CommunicationManager shareInstance].isDFUMode) {
        [[CommunicationManager shareInstance] disconnectThePeripheralWithCompletionBlock:^(BOOL success) {
            [CommunicationManager shareInstance].shouldRetryConnect = NO;
            [self performSelector:@selector(updateNordicFirmwave) withObject:nil afterDelay:3.0f];
        }];
    } else {        
        [[CommunicationManager shareInstance] performOperationType:OperationTypeUpdateDevice object:nil completionBlock:^(BOOL success, id feedbackData) {
            if (success) {
                NSLog(@"请求固件升级成功");
                
                [CommunicationManager shareInstance].shouldRetryConnect = NO;
                [self performSelector:@selector(updateNordicFirmwave) withObject:nil afterDelay:3.0f];
                
            } else {
                [self showFailAlertView];
                NSLog(@"咦..怎么走了这个咧");
                [self close];
            }
        }];
    }
    
}

- (void)updateNordicFirmwave
{
    [self centralManager:[LGCentralManager sharedInstance].manager didPeripheralSelected:[CommunicationManager shareInstance].lgPeripheral.cbPeripheral];
}

- (void)showFailAlertView
{
    FUIAlertView *alertView = [[FUIAlertView alloc] initWithTitle:NSLocalizedString(@"Reminder", nil) message:NSLocalizedString(@"The firmware upgrade failed, please try again", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"Yes", nil), nil];
    [alertView customizeAppearance];
    [alertView show];
}

- (void)showSuccessAlertView
{
    FUIAlertView *alertView = [[FUIAlertView alloc] initWithTitle:NSLocalizedString(@"Reminder", nil) message:NSLocalizedString(@"The firmware upgrade is successful, re-opening devices for Bluetooth connection", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"Yes", nil), nil];
    [alertView customizeAppearance];
    [alertView show];
}

#pragma mark - DFU

-(void)uploadPressed
{
    
    if (self.isTransferring) {
//        [dfuOperations cancelDFU];
    }
    else {
        [self performDFU];
    }
}

-(void)performDFU
{
    [self.dfuHelper checkAndPerformDFU];
}

- (void) clearUI
{         
//    selectedPeripheral = nil;
}

-(void)enableUploadButton
{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (selectedFileType && self.dfuHelper.selectedFileSize > 0) {
            if ([self.dfuHelper isValidFileSelected]) {
                NSLog(@" valid file selected");
            }
            else {
                NSLog(@"Valid file not available in zip file");
                [Utility showAlert:[self.dfuHelper getFileValidationMessage]];
                return;
            }
        }
        
        if (self.dfuHelper.isDfuVersionExist) {
            if (selectedPeripheral && selectedFileType && self.dfuHelper.selectedFileSize > 0 && self.isConnected && self.dfuHelper.dfuVersion > 1) {
                if ([self.dfuHelper isInitPacketFileExist]) {
                    [self uploadPressed];
                }
            }
            else {
                NSLog(@"cant enable Upload button");
            }
        }
        else {
            if (selectedPeripheral && selectedFileType && self.dfuHelper.selectedFileSize > 0 && self.isConnected) {
                [self uploadPressed];
            }
            else {
                NSLog(@"cant enable Upload button");
            }
        }
        
    });
}


-(void)appDidEnterBackground:(NSNotification *)_notification
{
    NSLog(@"appDidEnterBackground");
    if (self.isConnected && self.isTransferring) {
        [Utility showBackgroundNotification:[self.dfuHelper getUploadStatusMessage]];
    }
}

-(void)appDidEnterForeground:(NSNotification *)_notification
{
    NSLog(@"appDidEnterForeground");
    [[UIApplication sharedApplication] cancelAllLocalNotifications];
}

- (void)configureSelectedFileType:(NSString *)type
{
    selectedFileType = type;
    NSLog(@"unwindFileTypeSelector, selected Filetype: %@",selectedFileType);
    [self.dfuHelper setFirmwareType:selectedFileType];
    [self enableUploadButton];
}

#pragma mark Device Selection Delegate
-(void)centralManager:(CBCentralManager *)manager didPeripheralSelected:(CBPeripheral *)peripheral
{
    selectedPeripheral = peripheral;
    [dfuOperations setCentralManager:manager];
    [dfuOperations connectDevice:peripheral];
}

#pragma mark File Selection Delegate

-(void)onFileSelected:(NSURL *)url
{
    
    NSLog(@"onFileSelected");
    
    if (url) {
        
        NSString *selectedFileName = [[url path]lastPathComponent];
        //get last three characters for file extension
        NSString *extension = [selectedFileName substringFromIndex: [selectedFileName length] - 3];
        NSLog(@"selected file extension is %@",extension);
        if (!([extension isEqualToString: @"hex"] || [extension isEqualToString:@"zip"])) {
            return;
        }
        
        self.dfuHelper.selectedFileURL = url;
        NSLog(@"selectedFile URL %@",self.dfuHelper.selectedFileURL);
        
        NSData *fileData = [NSData dataWithContentsOfURL:url];
        self.dfuHelper.selectedFileSize = fileData.length;
        NSLog(@"fileSelected %@",selectedFileName);
        
        
        if ([extension isEqualToString:@"zip"]) {
            NSLog(@"this is zip file");
            self.dfuHelper.isSelectedFileZipped = YES;
            self.dfuHelper.isManifestExist = NO;
            [self.dfuHelper unzipFiles:self.dfuHelper.selectedFileURL];
        }
        else {
            self.dfuHelper.isSelectedFileZipped = NO;
        }
        
        dispatch_async(dispatch_get_main_queue(), ^{
            [self enableUploadButton];
        });
    }
    else {
        NSLog(@"Selected file not exist!");
    }
}

#pragma mark DFUOperations delegate methods

-(void)onDeviceConnected:(CBPeripheral *)peripheral
{
    NSLog(@"onDeviceConnected %@",peripheral.name);
    self.isConnected = YES;
    self.dfuHelper.isDfuVersionExist = NO;
    [self enableUploadButton];
}

-(void)onDeviceConnectedWithVersion:(CBPeripheral *)peripheral
{
    NSLog(@"onDeviceConnectedWithVersion %@",peripheral.name);
    self.isConnected = YES;
    self.dfuHelper.isDfuVersionExist = YES;
    [self enableUploadButton];
    
}

-(void)onDeviceDisconnected:(CBPeripheral *)peripheral
{
    NSLog(@"device disconnected %@",peripheral.name);
    self.isTransferring = NO;
    self.isConnected = NO;
    
    // Scanner uses other queue to send events. We must edit UI in the main queue

    self.isTransferCancelled = NO;
    self.isTransfered = NO;
    self.isErrorKnown = NO;
    
    if (!self.isFinishingApplication) {
        if (self.isFinishingBootLoader) {
            if (_retryCount < 3) {
                _retryCount++;
            } else {
                [[LGCentralManager sharedInstance] configureSetting];
                [self showFailAlertView];
                [self close];
                return;
            }
            [self configureSelectedFileType:FIRMWARE_TYPE_APPLICATION];
        } else {
            [self configureSelectedFileType:FIRMWARE_TYPE_BOTH_SOFTDEVICE_BOOTLOADER];
        }
        double delayInSeconds = 3.0;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [dfuOperations connectDevice:peripheral];
        });
    }
}

-(void)onReadDFUVersion:(int)version
{
    NSLog(@"onReadDFUVersion %d",version);
    self.dfuHelper.dfuVersion = version;
    NSLog(@"DFU Version: %d",self.dfuHelper.dfuVersion);
    if (self.dfuHelper.dfuVersion == 1) {
        [dfuOperations setAppToBootloaderMode];
    }
    [self enableUploadButton];
}

-(void)onDFUStarted
{
    NSLog(@"onDFUStarted");
    self.isTransferring = YES;
}

-(void)onDFUCancelled
{
    NSLog(@"onDFUCancelled");
    self.isTransferring = NO;
    self.isTransferCancelled = YES;
}

-(void)onSoftDeviceUploadStarted
{
    NSLog(@"onSoftDeviceUploadStarted");
}

-(void)onSoftDeviceUploadCompleted
{
    NSLog(@"onSoftDeviceUploadCompleted");
}

-(void)onBootloaderUploadStarted
{
    NSLog(@"onBootloaderUploadStarted");
}

-(void)onBootloaderUploadCompleted
{
    NSLog(@"onBootloaderUploadCompleted");
    self.isFinishingBootLoader = YES;
}

-(void)onTransferPercentage:(int)percentage
{
    NSLog(@"onTransferPercentage %d",percentage);
    // Scanner uses other queue to send events. We must edit UI in the main queue

    dispatch_async(dispatch_get_main_queue(), ^{
        NSString *processStr = [NSString stringWithFormat:@"%d%%", percentage];
        [self.processCircleChart updateChartByCurrent:@([processStr integerValue])];
    });
}

-(void)onSuccessfulFileTranferred
{
    NSLog(@"OnSuccessfulFileTransferred");
    // Scanner uses other queue to send events. We must edit UI in the main queue
    dispatch_async(dispatch_get_main_queue(), ^{
        self.isTransferring = NO;
        self.isTransfered = YES;
        
        NSString* message = [NSString stringWithFormat:@"%lu bytes transfered in %lu seconds", (unsigned long)dfuOperations.binFileSize, (unsigned long)dfuOperations.uploadTimeInSeconds];
        NSLog(@"%@", message);
        
        if (self.isFinishingBootLoader && [selectedFileType isEqualToString:FIRMWARE_TYPE_APPLICATION]) {
            self.isFinishingApplication = YES;
            self.isErrorKnown = NO;
            [[LGCentralManager sharedInstance] configureSetting];
            [self close];
        }
        
    });
}

-(void)onError:(NSString *)errorMessage
{
    NSLog(@"OnError %@",errorMessage);
    self.isErrorKnown = YES;
}


@end
